/* 完成日志器模块:
    1. 抽象日志器基类
    2. 派生出不同的子类 (同步日志器 && 异步日志器)
*/
#ifndef __M_LOGGER_M__
#define __M_LOGGER_M__
#include "util.hpp"
#include "level.hpp"
#include "format.hpp"
#include "looper.hpp"
#include "message.hpp"
#include "buffer.hpp"
#include "sink.hpp"
#include <assert.h>
#include <unordered_map>
#include <atomic>
#include <fstream>
#include <cstdarg>
#include <mutex>
namespace log
{
    class Logger
    {
        public:
        Logger(const std::string& logger_name,
        LogLevel::value limit_level,
        Formatter::ptr& formatter,
        std::vector<LogSink::ptr>& sinks):
        _logger_name(logger_name),
        _limit_level(limit_level),
        _formatter(formatter),
        _sinks(sinks)
        {
            ;
        }
        using ptr = std::shared_ptr<Logger>;
        /*完成构造日志消息对象过程并进行格式化，得到格式化后的日志消息字符串--然后进行落地输出*/
        void debug(const std::string& file,size_t line,const std::string fmt,...)
        {
            //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            //1. 判断当前的日志是否达到了输出等级
            if(LogLevel::value::DEBUG < _limit_level) return; 
            //2. 对fmt格式化字符串和不定参进行字符串组织,得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret ==-1)
            {
                std::cout << "vasprintf_failed!!!" <<std::endl;
                return;
            }
            va_end(ap);
            //3. 构造logMsg对象
            LogMsg msg(LogLevel::value::DEBUG,util::Date::now(),line,res,_logger_name,file);
            //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string str = _formatter->formate(msg);
            //5. 进行日志落地
            log(str.c_str(),str.size());
        }
        std::string get_loggerName()
        {
            return _logger_name;
        }
        void info(const std::string& file,size_t line,const std::string fmt,...)
        {
            //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            //1. 判断当前的日志是否达到了输出等级
            if(LogLevel::value::INFO < _limit_level) return; 
            //2. 对fmt格式化字符串和不定参进行字符串组织,得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret ==-1)
            {
                std::cout << "vasprintf_failed!!!" <<std::endl;
                return;
            }
            va_end(ap);
            //3. 构造logMsg对象
            LogMsg msg(LogLevel::value::INFO,util::Date::now(),line,res,_logger_name,file);
            //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string str = _formatter->formate(msg);
            //5. 进行日志落地
            log(str.c_str(),str.size());
        }
        void warn(const std::string& file,size_t line,const std::string fmt,...)
        {
            //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            //1. 判断当前的日志是否达到了输出等级
            if(LogLevel::value::WARN < _limit_level) return; 
            //2. 对fmt格式化字符串和不定参进行字符串组织,得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret ==-1)
            {
                std::cout << "vasprintf_failed!!!" <<std::endl;
                return;
            }
            va_end(ap);
            //3. 构造logMsg对象
            LogMsg msg(LogLevel::value::WARN,util::Date::now(),line,res,_logger_name,file);
            //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string str = _formatter->formate(msg);
            //5. 进行日志落地
            log(str.c_str(),str.size());
        }
        void error(const std::string& file,size_t line,const std::string fmt,...)
        {
            //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            //1. 判断当前的日志是否达到了输出等级
            if(LogLevel::value::ERROR < _limit_level) return; 
            //2. 对fmt格式化字符串和不定参进行字符串组织,得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret ==-1)
            {
                std::cout << "vasprintf_failed!!!" <<std::endl;
                return;
            }
            va_end(ap);
            //3. 构造logMsg对象
            LogMsg msg(LogLevel::value::ERROR,util::Date::now(),line,res,_logger_name,file);
            //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string str = _formatter->formate(msg);
            //5. 进行日志落地
            log(str.c_str(),str.size());
        }
        void fatal(const std::string& file,size_t line,const std::string fmt,...)
        {
            //通过传入的参数构造出一个日志消息对象，进行日志的格式化，最终落地
            //1. 判断当前的日志是否达到了输出等级
            if(LogLevel::value::FATAL < _limit_level) return; 
            //2. 对fmt格式化字符串和不定参进行字符串组织,得到的日志消息的字符串
            va_list ap;
            va_start(ap,fmt);
            char* res;
            int ret = vasprintf(&res,fmt.c_str(),ap);
            if(ret ==-1)
            {
                std::cout << "vasprintf_failed!!!" <<std::endl;
                return;
            }
            va_end(ap);
            //3. 构造logMsg对象
            LogMsg msg(LogLevel::value::FATAL,util::Date::now(),line,res,_logger_name,file);
            //4. 通过格式化工具对LogMsg进行格式化，得到格式化后的日志字符串
            std::string str = _formatter->formate(msg);
            //5. 进行日志落地
            log(str.c_str(),str.size());
        }

        protected:
        /*抽象接口完成实际的落地输出--不同的日志器会有不同的实际落地方式*/
        virtual void log(const char* data,size_t len) =0;

        protected:
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
        std::mutex _mutex;
    };

    class AsyncLogger: public Logger
    {
        public:
        AsyncLogger(const std::string& logger_name,
        LogLevel::value limit_level,
        Formatter::ptr& formatter,
        std::vector<LogSink::ptr>& sinks,
        log::AsyncType asynctype):
        Logger(logger_name,limit_level,formatter,sinks),
        _asyncLooper(std::make_shared<log::AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),
        asynctype))
        {
            ;
        }
        //将数据写入缓冲区
        void log(const char* data,size_t len) override 
        {
            _asyncLooper->push(data,len);
        }
        void realLog(Buffer& buffer) //设计一个实际落地函数(将缓冲区中的数据落地)
        {
            if(_sinks.empty()) return;
            for(auto& it: _sinks)
            {
                it->log(buffer.begin(),buffer.readablesize());
            }
        }
        private:
        log::AsyncLooper::ptr _asyncLooper;
    };

    class SyncLogger : public Logger
    {
        public:
        SyncLogger(const std::string& logger_name,
        LogLevel::value limit_level,
        Formatter::ptr& formatter,
        std::vector<LogSink::ptr>& sinks):
        Logger(logger_name,limit_level,formatter,sinks)
        {
            ;
        }
        //同步日志器，是将日志直接通过落地模板句柄进行日志落地
        
        protected:
        void log(const char*data,size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if(_sinks.empty()) return;
            for(auto& it: _sinks)
            {
                it->log(data,len);
            }
        }
    };

    enum class Logger_type
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    /*使用建造者模式来建造日志器，而不要让用户直接去构造日志器，简化用户的使用复杂度*/
    //1. 抽象一个日志器建造者(完成日志器对象所需零部件的构建 & 日志器的构建)
    // 2. 设置日志器的类型
    // 3. 将不同类型日志器的创建放到同一个日志器建造类中完成
    class LoggerBuilder
    {
        public:
        LoggerBuilder()
        :_logger_type(Logger_type::LOGGER_SYNC),
        _limit_level(log::LogLevel::value::DEBUG),
        _asyncType(log::AsyncType::ASYNC_SAFE),
        _logger_name()
        {
            ;
        }
        void buildLoggerType(Logger_type type) {_logger_type = type;}
        void buildLoggerName(const std::string& name) {_logger_name = name;}
        void buildFormatter(const std::string& pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        void buildEnableUnSafeAsync(){_asyncType = log::AsyncType::ASYNC_UNSAFE;  }
        void buildLoggerLevel(log::LogLevel::value level) {_limit_level = level;}
        template<class SinkType,class ...Args>
        void buildSink(Args&& ...args)
        {
            LogSink::ptr psink = log::SinkFactory::Create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual Logger::ptr build() =0;
        protected:
        log::AsyncType _asyncType;
        log::Logger_type _logger_type;
        std::string _logger_name;
        log::LogLevel::value _limit_level;
        Formatter::ptr _formatter = nullptr;
        std::vector<log::LogSink::ptr> _sinks;
    };
    
    //2. 派生类具体的建造者类--局部日志器的建造者 & 全局的日志器的建造者 (后变添加了全局单例管理器之后，将日志器添加全局管理)
    class LocalloggerBuilder:public LoggerBuilder
    {
        public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>("[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"); 
            }
            if(_sinks.empty())
            {
                _sinks.push_back(log::SinkFactory::Create<log::StdoutSink>());
            }
            if(_logger_type == log::Logger_type::LOGGER_ASYNC)
            {
                return std::make_shared<log::AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_asyncType);
            }
            return std::make_shared<log::SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
        }
    };


    class LoggerManager
    {
        public:
        void addLogger(const log::Logger::ptr& logger)
        {
            if(hasLogger(logger->get_loggerName()) == true)
            {
                std::cout << "添加Logger:" << logger->get_loggerName() << "失败" <<std::endl;
                return;
            };
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->get_loggerName(),logger));
        }
        bool hasLogger(const std::string& logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it =   _loggers.find(logger_name);
            if(it == _loggers.end()) return false;
            return true;
        }
        log::Logger::ptr getLogger(const std::string& logger_name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it =   _loggers.find(logger_name);
            if(it == _loggers.end()) return nullptr;
            return it->second; 
        }
        log::Logger::ptr rootLogger()
        {
            return  _default_logger;
        }
        static LoggerManager& getInstance()
        {
            //c++11之后，针对静态局部变量，编译器在编译的层面实现了线程安全
            static log::LoggerManager _loggerManager;
            return _loggerManager;
        }
        private:
        LoggerManager()
        {
            std::unique_ptr<log::LoggerBuilder> localBuilder(new log::LocalloggerBuilder());
            localBuilder->buildLoggerName("root");
            _default_logger = localBuilder->build();
            _loggers.insert(std::make_pair("root",_default_logger));
        }
        private:
        std::mutex _mutex;
        std::unordered_map<std::string,log::Logger::ptr> _loggers;
        log::Logger::ptr _default_logger; //默认日志器
    };
        //设计一个全局日志器的建造者--在局部的基础上增加了一个功能，将日志器添加到单例对象中
    class GloballoggerBuilder:public LoggerBuilder
    {
        public:
        Logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>("[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n"); 
            }
            if(_sinks.empty())
            {
                _sinks.push_back(log::SinkFactory::Create<log::StdoutSink>());
            }
            log::Logger::ptr logger;
            if(_logger_type == log::Logger_type::LOGGER_ASYNC)
            {
                logger= std::make_shared<log::AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_asyncType);
            }
            else
            {
                logger= std::make_shared<log::SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }
            log::LoggerManager::getInstance().addLogger(logger);
            return logger;
        }
    };
}
#endif
